 
#ifndef __RSP_C_OBJLIST__HEADER_FILE__
#define __RSP_C_OBJLIST__HEADER_FILE__

#include "viewcont.h"
#include "c_object.h"
#include "coid/comm/token.h"

using namespace coid;

////////////////////////////////////////////////////////////////////////////////
class rsp_c_objlist : public rsp_base
{
public:

    void frame()
    {
    }

    void command( uchar cd, binstream& bin )
    {
        if( cd == OBJLIST_OP::OL_INS )
        {
            uchar s;
            bin >> s;
            charstr cls;
            bin.xread_raw( cls.get_buf(s), s );

            ushort pos,oid;
            bin >> pos >> oid;

            rsp_c_object_state::fnc_create_object fn;
            fn = rsp_c_object_state::find_class(cls);
            RASSERT(fn);

            //create ref object at the given position
            rsp_base* p = fn(0);
            //p->set_oid(oid);
            _vc.view_set( pos, new rsp_c_object_state(p,oid) );
        }
        else if( cd == OBJLIST_OP::OL_DEL )
        {
            ushort pos;
            bin >> pos;

            _vc.view_del( pos, true );
        }
        else if( cd == OBJLIST_OP::OL_OWN )
        {
            ushort pos;
            bin >> pos;

            _owned = _vc.view_get(pos);
            _owned->create_local_buffer();
        }
        else
            RASSERT(0);
    }

    RSP_CLASS_NAME("$",rsp_c_objlist)


    void stream_in( binstream& bin )
    {
        MARK_IN('$');
        ushort cnt;
        bin >> cnt;

        _vc.resize( cnt, true );

        charstr cls;

        for( ushort i=0; i<cnt; ++i )
        {
            uchar s;
            bin >> s;
            bin.xread_raw( cls.get_buf(s), s );

            ushort oid;
            bin >> oid;

            rsp_c_object_state* os = _vc.view_get(i);
            if( os && os->object_ptr() )
            {
                if( os->oid() == oid  &&  os->class_name() == cls )
                    continue;

                if( os->class_name() == cls ) {
                    _vc.view_unreg(i);
                    _vc.view_reg( i, os->object_ptr(), oid );
                    continue;
                }

                _vc.view_del_slot( i, true );
            }

            if( i > 0 )
            {
                rsp_c_object_state::fnc_create_object fn;
                fn = rsp_c_object_state::find_class(cls);
                RASSERT(fn);

                //create ref object at the given position
                rsp_base* p = fn(0);
                //p->set_oid(oid);
                _vc.view_reg( i, p, oid );
            }
            else {
                //set_oid(oid);
                _vc.view_reg( i, this, oid );
            }
        }

        ushort own;
        bin >> own;
        if( own != WMAX )
        {
            rsp_c_object_state* owned = _vc.view_get(own);
            if( _owned != owned ) {
                if(_owned)
                    _owned->destroy_local_buffer();
                _owned = owned;
                _owned->create_local_buffer();
            }
            //else if(_owned)
            //    _owned->reset_local_buffer();
        }
        MARK_IN('$'|0x80);
    }

    void stream_out( binstream& bin )
    {
        DASSERT(0);
    }

    bool patch( rsp_c_update& upd )
    {
        ushort n;
        *upd._bin >> n;
        if( n == 0 )
            return true;

        _mask.need_new_bits(n);
        upd._bin->xread_raw( _mask.ptr(), _mask.byte_size() );

        for( uint i=0; i<(uint)n; ++i )
        {
            if( !_mask.get_bit(i) ) {
                DASSERT( !upd._full );
                continue;
            }

            if( i >= _vc._views.size()  ||  _vc._views[i] == 0 )
                _vc.view_set( i, new rsp_c_object_state, false );

            _vc._views[i]->read_diff(upd);
        }

        return true;
    }


    ///Do one physics step on every managed object
    void process_bound_frame( uint frame )
    {
        if(_owned)
            _owned->prepare_frame(frame);

        uints n = _vc._views.size();
        {for( uints i=0; i<n; ++i )
            _vc._views[i]->frame_bnd(frame);
        }
    }

    ///@return >0 if bound state should be reset
    uint process_ref_frame()
    {
        uint bsr=0;     //bound state reset

        uint n = _vc._views.size();
        {for( uint i=0; i<n; ++i ) {
            bsr += _vc._views[i]->frame_ref();
        }}

        if(_owned)
            _owned->eat_local_command();

        return process_ref_frame_final(bsr);
    }

    uint process_ref_frame_final( uint bsr )
    {
        uint n = _vc._views.size();
        {for( uint i=0; i<n; ++i )
            bsr += _vc._views[i]->frame_ref_final();
        }

        return bsr;
    }

    void eat_local_commands( uint n )
    {
        if(_owned)
            _owned->eat_local_commands(n);
    }

    void sync_bound_objects()
    {
        uint n = _vc._views.size();
        {for( uint i=0; i<n; ++i )
            _vc._views[i]->sync_bound();
        }
    }


    rsp_c_object_state* get_object( uint n ) const
    {
        return _vc._views[n];
    }

    rsp_c_object_state* find_object( rsp_base* p ) const
    {
        return _vc.view_find( p->oid() );
    }

    rsp_c_object_state* find_object( uint oid ) const
    {
        return _vc.view_find( oid );
    }

    rsp_c_object_state* get_owned_object( const token& cls )
    {
        if(!_owned)  return 0;
        if( _owned->class_name() != cls )  return 0;
        return _owned;
    }

    rsp_c_object_state* get_owned_object()
    {
        if(!_owned)  return 0;
        return _owned;
    }


    rsp_c_objlist()
    {
        _owned = 0;
        _vc.view_add( new rsp_c_object_state(this, UMAX) );
        
        created();
    }

protected:

    //
    rsp_c_object_state* _owned;

    dynarray<uint8> _mask;

    rsp_ref_container<rsp_c_object_state> _vc;
};


#endif //__RSP_C_OBJLIST__HEADER_FILE__
